package com.cictec.middleware.core.service;

import java.math.BigDecimal;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.cictec.middleware.commons.utils.Constants;
import com.cictec.middleware.commons.utils.PMSUtils;
import com.cictec.middleware.commons.utils.ZoneUtils;
import com.cictec.middleware.core.entity.BusLine;
import com.cictec.middleware.core.entity.BusLineMapPoint;
import com.cictec.middleware.core.entity.BusLineStation;
import com.cictec.middleware.core.entity.StandbyZone;
import com.cictec.middleware.core.mapper.BusLineMapper;

/**
 * 车辆线路、站点服务
 * 
 * @author ql
 *
 */
@SuppressWarnings({ "rawtypes", "unchecked" })
@Service
public class BusLineService {

	public static Logger logger = LoggerFactory.getLogger(BusLineService.class);

	@Autowired
	private BusLineMapper busLineMapper;

	@Autowired
	private BusLineMapPointService busLineMapPointService;
	@Autowired
	private BusLineStandbyService busLineStandbyService;
	@Autowired
	private BusLineStataionService busLineStataionService;

	/**
	 * 线路集合 key--> lineId 设备线路号
	 */
	private ConcurrentMap<Integer, BusLine> lineMap = new ConcurrentHashMap<Integer, BusLine>();

	public void loadLineInfo(String lineUuid) {
		/*
		 * 加载线路信息 1、线路基础信息 2、线路地图点坐标信息 3、线路站点信息 4、线路待发区信息
		 */

	}

	/**
	 * 刷新线路信息【基础信息、线路站点信息、线路地图信息、线路待发区信息】
	 * 
	 * @param lineUuid
	 */
	public void reloadLineInfo(String lineUuid) {

		reloadLine(lineUuid);

		busLineStataionService.reloadLineStation(lineUuid, "1");
		busLineStataionService.reloadLineStation(lineUuid, "2");

		busLineMapPointService.reloadBusLineMapPoint(lineUuid, "1"); // 上行
		busLineMapPointService.reloadBusLineMapPoint(lineUuid, "2"); // 下行

		busLineStandbyService.reloadLineStandyInfo(lineUuid);

		logger.debug("【线路信息】刷新线路 {} 基础缓存信息", lineUuid);
		logger.debug("【线路信息】刷新线路 {} 站点缓存信息", lineUuid);
		logger.debug("【线路信息】刷新线路 {} 地图缓存信息", lineUuid);
	}

	/**
	 * 刷新线路基础信息
	 * 
	 * @param lineUuid
	 */
	public void reloadLine(String lineUuid) {

		BusLine busLine = selectLineByLineUuid(lineUuid);
		if (busLine != null) {
			for (Integer _lineIds : busLine.getBusLineIds()) {
				lineMap.putIfAbsent(_lineIds, busLine);
			}
		}
	}
	
	/**
	 * 获取所有线路信息
	 * 
	 * @return
	 */
	public List<BusLine> getListBusLine() {

		// 查询所有线路信息
		List<BusLine> lineList = selectLineByParams(new HashMap());
		for (BusLine busLine : lineList) {
			List<Integer> busLineIds = selectBusLineIds(busLine.getLineUuid());
			busLine.setBusLineIds(busLineIds);
		}
		return lineList;
	}

	public List<Integer> selectBusLineIds(String lineUuid) {
		return busLineMapper.selectBusLineIds(lineUuid);
	}


	/**
	 * 根据lineUuid查询线路信息
	 * 
	 * @param lineUuid
	 * @return
	 */
	public BusLine getLineByLineUuid(String lineUuid) {

		for (BusLine busLine : lineMap.values()) {
			if (busLine.getLineUuid().equals(lineUuid)) {
				return busLine;
			}
		}

		BusLine busLine = selectLineByLineUuid(lineUuid);
		if (busLine != null) {
			for (Integer _lineIds : busLine.getBusLineIds()) {
				lineMap.putIfAbsent(_lineIds, busLine);
			}
		}

		return busLine;
	}

	/**
	 * 根据设备线路号 查询线路信息
	 * 
	 * @param lineId
	 * @return
	 */
	public BusLine getLineByDeivceLineId(String lineId) {
		return getLineByDeivceLineId(Integer.parseInt(lineId));
	}

	/**
	 * 根据设备线路号 查询线路信息
	 * 
	 * @param lineId
	 * @return
	 */
	public BusLine getLineByDeivceLineId(int lineId) {

		BusLine line = null;

		for (Integer _lineId : lineMap.keySet()) {
			if(_lineId == lineId){
				line = lineMap.get(_lineId);
				break;
			}
		}
		return line;
	}

	/** 获取发车类型（0单向 ，1双向，2环线） */
	public Integer getLineBfType(String lineUuid) {
		BusLine busLine = getLineByLineUuid(lineUuid);
		if (busLine != null) {
			return busLine.getLineBfType();
		}
		return null;
	}

	/**
	 * 【数据库】查询线路信息
	 * 
	 * @param lineId
	 *            设备线路号
	 * @return
	 */
	public BusLine selectLineByDeivceLineId(int lineId) {
		Map parMap = new HashMap();
		parMap.put("lineId", lineId);
		return selectOneLineByParams(parMap);
	}

	/**
	 * 【数据库】根据线路lineUuid查询线路
	 * 
	 * @param lineUuid
	 * @return
	 */
	public BusLine selectLineByLineUuid(String lineUuid) {
		Map parMap = new HashMap();
		parMap.put("lineUuid", lineUuid);

		BusLine busLine = selectOneLineByParams(parMap);
		if(busLine != null){
			List<Integer> busLineIds = selectBusLineIds(busLine.getLineUuid());
			busLine.setBusLineIds(busLineIds);
		}
		return busLine;
	}

	/**
	 * 【数据库】根据参数查询线路
	 * 
	 * @param parMap
	 * @return
	 */
	public BusLine selectOneLineByParams(Map params) {
		return busLineMapper.selectBusLineByParams(params);
	}

	/**
	 * 【数据库】根据条件查询线路信息
	 * 
	 * @param lineId
	 * @return
	 */
	public List<BusLine> selectLineByParams(Map params) {

		return busLineMapper.selectListBusLineByParams(params);
	}

	/**
	 * 获取线路上车辆待发区【缓存中取，没有的时候取数据库】
	 * 
	 * @param lineUuid
	 * @return
	 */
	public List<StandbyZone> getStandbyZones(String lineUuid) {

		return busLineStandbyService.getStandbyZones(lineUuid);
	}

	/**
	 * 【缓存】获取线路上所有站点信息
	 * 
	 * @param lineUuid
	 * @param lineType
	 * @return
	 */
	public List<BusLineStation> getLineStationAll(String lineUuid, String lineType) {
		return busLineStataionService.getLineStationAll(lineUuid, lineType);
	}

	/**
	 * 【缓存】获取线路的第一个站点信息
	 * 
	 * @param lineUuid
	 * @param lineType
	 * @return
	 */
	public BusLineStation getLineStationFirst(String lineUuid, String lineType) {
		return busLineStataionService.getLineStationFirst(lineUuid, lineType);
	}

	public BusLineStation getLineStationLast(String lineUuid, String lineType) {
		return busLineStataionService.getLineStationLast(lineUuid, lineType);
	}

	/**
	 * 根据 线路uuid， 上传数据站点编号，查询当前站点（线路上下行）信息
	 * 
	 * @param lineUuid
	 * @param lineType
	 * @param stationSeq
	 * @return
	 */
	public BusLineStation getLineStationByStationSeq(String lineUuid, String lineType, int stationSeq) {
		return busLineStataionService.getLineStationByStationSeq(lineUuid, lineType, stationSeq);
	}

	public BusLineStation getLineStationByStationSeq(String lineUuid, String lineType, String stationSeq) {
		return busLineStataionService.getLineStationByStationSeq(lineUuid, lineType, Integer.parseInt(stationSeq));
	}

	public BusLineStation getLineStationByStationSeq(String lineUuid, int stationSeq) {
		return busLineStataionService.getLineStationByStationSeq(lineUuid, stationSeq);
	}

	/**
	 * 根据位置信息（坐标）获取站点信息
	 * 
	 * @param lineUuid
	 * @param lineType
	 * @param lat
	 * @param lng
	 * @return
	 */
	public List<BusLineStation> getLineStationByPosition(String lineUuid, String lineType, String lat, String lng) {
		return busLineStataionService.getLineStationByPosition(lineUuid, lineType, Double.parseDouble(lat),
				Double.parseDouble(lng));
	}

	/**
	 * 根据位置信息（坐标）获取站点信息（如果存储，则点落在给站点围栏内【进站状态】）
	 * 
	 * @param lineUuid
	 * @param lineType
	 * @param lat
	 * @param lng
	 * @return
	 */
	public List<BusLineStation> getLineStationByPosition(String lineUuid, String lineType, double lat, double lng) {
		return busLineStataionService.getLineStationByPosition(lineUuid, lineType, lat, lng);
	}

	/**
	 * 判定当前站是否是第{x}站 <br>
	 * 根据线路类型判定，如果是单向、双向发车，lineType不为null的时候，取指定上下行总的站点排序
	 * 
	 * @param lineUuid
	 *            线路UUID
	 * @param lineType
	 *            线路类型
	 * @param stationSequence
	 *            当前站站序
	 * @param stationIndex
	 *            是否是第x站, x>0整数第几站, x<0倒数第几站, x=0返回false,不做判定
	 * @return
	 */
	public boolean isLineStationByIndex(String lineUuid, String lineType, int stationSequence, int stationIndex) {
		return busLineStataionService.isLineStationByIndex(lineUuid, lineType, stationSequence, stationIndex);
	}

	public boolean isLastLineStation(String lineUuid, String lineType, String stationSequence) {
		return busLineStataionService.isLastLineStation(lineUuid, lineType, Integer.parseInt(stationSequence));
	}

	/**
	 * 根据位置信息（坐标）获取站点信息（gps点不再站点围栏内，根据该点，倒序取经过的第一个站点，即为该站点的出站状态【出站状态】）
	 * 
	 * @return
	 */
	public BusLineStation getNearstBusLineStation(String lineUuid, String lineType, String latitude, String longitude) {

		BusLineStation lineStation = null;
		List<BusLineMapPoint> points = busLineMapPointService.getBusLineMapPoint(lineUuid, lineType);
		BusLineMapPoint point = busLineMapPointService.getNearstPoint(lineUuid, lineType, latitude, longitude);
		int nearstPointIndex = point.getMlSequence() - 1; // 真是游标
		for (int i = nearstPointIndex; i < points.size(); i--) {

			// 找到最近的一个刚出的站序
			if (points.get(i).getMlWhichstop() > 0) {
				int tmpSeq = points.get(i).getMlWhichstop();
				lineStation = getLineStationByStationSeq(lineUuid, lineType, tmpSeq);
				break;
			}
		}
		return lineStation;
	}

	/**
	 * 根据gps坐标获取线路上最近的线路点(获取该点前后位置的点，最多3个点，最少2个点)
	 * 
	 * @param lineUuid
	 * @param lineType
	 * @param latitude
	 * @param longitude
	 * @return
	 */
	public List<BusLineMapPoint> getNearstPoints(String lineUuid, String lineType, String latitude, String longitude) {
		return busLineMapPointService.getNearstPoints(lineUuid, lineType, latitude, longitude);
	}

	/**
	 * 相对距离计算（站点间相对距离）
	 * 
	 * @param lineUuid
	 * @param lineType
	 * @param latitude
	 * @param longitude
	 * @param lineStationSeq
	 * @param enterOutStatus
	 * @return
	 */
	public double caculateRealtiveDistanceByStation(String lineUuid, String lineType, String latitude, String longitude,
			String lineStationSeq, String enterOutStatus) {
		// 计算车辆的相对位置
		double rate = 0;
		if (PMSUtils.isEmpty(lineStationSeq)) {
			return rate;
		}

		if (enterOutStatus.equals(Constants.VAL_ENTER_OUT_SATION_ENTER)) {
			// 进站状态，相对位置都为0
			rate = 0;
		} else {
			if (!PMSUtils.isEmpty(lineStationSeq)) {
				int orgStationSeq = Integer.parseInt(lineStationSeq) - 1; // 原来出站站序
				if (orgStationSeq < 1) {
					orgStationSeq = 1;
				}
				BusLineMapPoint startStationPoint = busLineMapPointService.getBusLineMapPoint(lineUuid, lineType,
						orgStationSeq);
				BusLineMapPoint endStaionPoint = busLineMapPointService.getBusLineMapPoint(lineUuid, lineType,
						orgStationSeq + 1);
				if (endStaionPoint == null) {
					return rate;
				}

				List<BusLineMapPoint> nearPoints = busLineMapPointService.getBusLineMapPoint(lineUuid, lineType,
						orgStationSeq, orgStationSeq + 1);
				if (nearPoints.size() > 0) {

					double lineLength = endStaionPoint.getMlDistance() - startStationPoint.getMlDistance();
					double relativeValue = ZoneUtils.relativeValue(nearPoints, latitude, longitude, lineLength);
					rate = new BigDecimal(relativeValue).setScale(3, BigDecimal.ROUND_HALF_UP).doubleValue();
				}
			}
		}
		return rate;
	}

	/**
	 * 相对距离计算（站点间相对距离）【依赖线路相对距离】
	 * 
	 * @param lineUuid
	 * @param lineType
	 * @param enterOutStatus
	 * @param lineStationSeq
	 * @param rateInLine
	 * @return
	 */
	public double caculateRealtiveDistanceByStation(String lineUuid, String lineType, String enterOutStatus,
			String lineStationSeq, Double rateInLine) {

		// 计算车辆的相对位置
		double rate = 0;
		if (enterOutStatus.equals(Constants.VAL_ENTER_OUT_SATION_ENTER)) {
			// 进站状态，相对位置都为0
			rate = 0;
		} else {

			if (!PMSUtils.isEmpty(lineStationSeq)) {

				int orgStationSeq = Integer.parseInt(lineStationSeq) - 1; // 原来出站站序
				if (orgStationSeq < 1) {
					orgStationSeq = 1;
				}
				List<BusLineMapPoint> lineMapPoints = busLineMapPointService.getBusLineMapPoint(lineUuid, lineType);

				if (lineMapPoints.size() == 0 || rateInLine == 0) {
					return rate;
				}

				// 站点相对距离
				double totalLength = lineMapPoints.get(lineMapPoints.size() - 1).getMlDistance(); // 总长度
				double totalRate = rateInLine; // 线路相对距离百分比
				BusLineMapPoint startStationPoint = busLineMapPointService.getBusLineMapPoint(lineUuid, lineType,
						orgStationSeq);
				double startStationLength = startStationPoint.getMlDistance(); // 起始位置距离当前站距离

				BusLineMapPoint endStaionPoint = busLineMapPointService.getBusLineMapPoint(lineUuid, lineType,
						orgStationSeq + 1);
				if (endStaionPoint == null) {
					// 下一站为null（主要是报站站点数文件与服务器站点数不相符合）
					rate = 0;
					logger.error("【相对位置】报站站点数文件与服务器站点数不相符合 lineUuid:{}, lineType:{}, orgSeq:{}已经是最后一站了, 没有下一个站点信息",
							lineUuid, lineType, orgStationSeq);
				} else {
					double endStationLength = endStaionPoint.getMlDistance(); // 起始位置距离当前站距离

					rate = (totalLength * totalRate - startStationLength) / (endStationLength - startStationLength);
					BigDecimal bg = new BigDecimal(rate);
					rate = bg.setScale(3, BigDecimal.ROUND_HALF_UP).doubleValue();
				}
			}
		}
		return rate;
	}

	/**
	 * 相对距离计算（总线路相对距离）
	 * 
	 * @param mapLines
	 * @param latitude
	 * @param longitude
	 * @param stationSeq
	 *            (站点信息可能导致问题，详见方法说明)，所以次值可设置null
	 * @return
	 */
	public double caculateRealtiveDistanceByLine(String lineUuid, String lineType, String latitude, String longitude,
			Integer stationSeq) {
		List<BusLineMapPoint> lineMapPoints = busLineMapPointService.getBusLineMapPoint(lineUuid, lineType);
		List<BusLineMapPoint> nearPoints = busLineMapPointService.getNearstPoints(lineMapPoints, latitude, longitude,
				stationSeq);
		// List<BusLineMapPoint> nearPoints =
		// busLineMapPointService.getNearstPoints(lineMapPoints, latitude,
		// longitude, null);

		// 计算车辆的相对位置
		double rate = 0;
		try {
			if (lineMapPoints.size() > 0) {
				double lineLength = lineMapPoints.get(lineMapPoints.size() - 1).getMlDistance();
				double relativeValue = ZoneUtils.relativeValue(nearPoints, latitude, longitude, lineLength);
				rate = new BigDecimal(relativeValue).setScale(3, BigDecimal.ROUND_HALF_UP).doubleValue();
			}
		} catch (Exception e) {
			e.printStackTrace();
			logger.error(e.getMessage());
		}
		return rate;
	}

	/**
	 * 判定GPS点是否偏离线路
	 * 
	 * @param lineUuid
	 * @param lineType
	 * @param lat
	 * @param lng
	 * @return
	 */
	public boolean isDeviate(String lineUuid, String lineType, Double lat, Double lng) {
		return isDeviate(lineUuid, lineType, String.valueOf(lat), String.valueOf(lng));
	}

	/**
	 * 判定GPS点是否偏离线路
	 * 
	 * @param lineUuid
	 * @param lineType
	 * @param lat
	 * @param lng
	 * @return
	 */
	public boolean isDeviate(String lineUuid, String lineType, String lat, String lng) {
		List<BusLineMapPoint> points = busLineMapPointService.getNearstPoints(lineUuid, lineType, lat, lng);
		return busLineMapPointService.isDeviate(points, lat, lng);
	}

}
